/**
 * このサンプルは、Audio Data APIを検証するためのものです。
 * https://wiki.mozilla.org/Audio_Data_APIをベースにいろいろ弄っています。
 * 
 * @version 0.01
 * @lastUpdate 2010-10-09
 * @author kensaku KOMATSU(kensaku.komatsu@gmail.com)
 */

///////////////////////////////////////////////////////////////
// Web Socket 関連の定義
///////////////////////////////////////////////////////////////
var socket = new io.Socket('localhost',{port:3000}); 

socket.connect();

var re_s = 0, cur_re = -1, re_d = 0, bufferes = [], re_flag = true;

//データ受信ハンドラ　dataは受信データ（UTF-8 character)
socket.on('message', function(data){
	if (re_flag) {
		re_s = new Date().getTime();
		re_flag = false;
	}
	// 受信レートを計算する（1秒ごとに更新）
	var cur = new Date().getTime();
	var dur = Math.floor((cur - re_s)/1000);
	
	if(dur != cur_re) {
		cur_re = dur;
		$('#arr').html(re_d+"[bytes/sec]");
		re_d = 0;
	}
	re_d += data.length;

	///////////////////////////////////////
	// 受信データをFloat32Arrayに変換し、
	// バッファに格納する
	////////////////////////////////////////
	try {
		var _recvdata = JSON.parse(data);
		var _len = frameBufferLength / channels;
		var signal = new Float32Array(_len);
		for(var i = 0; i < _len; i++) {
			signal[i] = _recvdata[i];
		}
		bufferes.push(signal);
	} catch(e){}
});

//////////////////////////////////////////////////////
// 再生バッファ
//////////////////////////////////////////////////////
var bufferes = [];
var interval = null;
var p_flag  = false;
var bufferedPlay = function(){
	var buflen = bufferes.length;
	if (!p_flag && buflen > 20) 
		p_flag = true;
	if (p_flag && buflen < 10) 
		p_flag = false;
	var _interval = buflen > 30 ? interval - 10 : interval;
	if (p_flag) {
		writeAudio(bufferes.shift());
		$('#bufflen').html(buflen + " : " + _interval);
	}
	setTimeout(bufferedPlay, _interval);
}


///////////////////////////////////////////////////////
// ここからAudio Data API関連
///////////////////////////////////////////////////////
/**
 * MetaDataが読み込まれたときに呼ばれるハンドラー
 * Initialize global properties for handling audio data api.
 */
function loadedMetadata(){
    channels = inaudio.mozChannels;
    rate = inaudio.mozSampleRate;
    frameBufferLength = inaudio.mozFrameBufferLength;
	interval = 1000/(rate/(frameBufferLength/channels)) - 5;
	$("#metadatas").html("channel = "+channels+", rate = "+rate+", frameBufferLength = "+frameBufferLength);
	
	// 入力をMuteする
	inaudio.volume = 0;
	// 出力Audioインスタンスを入力値(ただし、モノラル)でセットアップする。
	outaudio.mozSetup(1, rate);
	bufferedPlay(); // 再生バッファをスタート
}




/**
 * Audio Dataが生成される都度、callされるhandler
 * audio.mozFrameBufferLengthがfullになる度にコールされる。
 * 例えばサンプリング周波数が44.1kHzで、チャンネルが2（ステレオ）の場合
 * 秒間 44100 x 2 = 88200回Ampliferデータが生成される。
 * ここで、上記BufferLength=2048の場合
 * 88200 / 2048 = 43.16...
 * となり、秒間約43回コールされる pureで単純にstringifyすると16Mbps程度のデータ量。。。
 * 
 * @param {Object} event
 */
var curSec = -1, curFreq = 0, curByte = 0;
function audioAvailable(event){
    var fb = event.frameBuffer, t = event.time, /* time duration */
		signal = new Float32Array(fb.length / channels);
    
	
	if(Math.floor(t) != curSec) {
		if(curSec != -1) {
			$('#aar').html(curByte+" [bytes/sec]");
		}
		curSec = Math.floor(t);
		curFreq = 0;
		curByte = 0;
	}
	curFreq++;
	
    // 以下は、ステレオチャネル決め打ちのコード。モノラルオーディオに変換している。
    for (var i = 0, fbl = frameBufferLength / 2; i < fbl; i++) {
        signal[i] = (fb[2 * i] + fb[2 * i + 1]) / 2;
    }
	
	var sendData = JSON.stringify(signal);
	
	socket.send(sendData);
	
	curByte+=sendData.length;
}

/**
 * 振幅dataより再生する。
 * @param {Object} audio
 */
var outaudio = new Audio(), buffers = [];
function writeAudio(audio) {
  buffers.push(audio);
  // バッファデータがあれば再生
  while(buffers.length > 0) {
    var buffer = buffers.shift();
    var written = outaudio.mozWriteAudio(buffer);
    // 全て再生できなかったデータは、バッファに再度格納
    if(written < buffer.length) {
      buffers.unshift(buffer.slice(written));
      return;
    }
  }
}

/////////////////////////////////////////////////////
// 開始
/////////////////////////////////////////////////////
var inaudio = document.getElementById('audio-element');
inaudio.addEventListener('MozAudioAvailable', audioAvailable, false); // オーディオデータ取得時
inaudio.addEventListener('loadedmetadata', loadedMetadata, false); // オーディオデータロード完了時

